import React, { useEffect, useState } from "react";
import "./index.less";
import { Button, Card, message, Table, Modal, Form, Input, Select } from "antd";
import { PlusOutlined } from "@ant-design/icons";
import MyButton from "../../components/MyButton";
import { addCategory, reqCategory, updateCategory } from "../../api";
import ArrowRightOutlined from "@ant-design/icons/lib/icons/ArrowRightOutlined";
const { Option } = Select;

const Category: React.FC = () => {
  // 这个tempId用来暂存table表格中我所点击的那一行的数据的_id 用来给点击修改事件传入参数
  const [tempId, settempId] = useState("");

  // 一级分类列表  也即是antd tlble的数据源
  const [categorys, setcategorys] = useState([]);

  // 子分类列表
  const [subCategory, setsubCategory] = useState([]);

  // 是否正在请求数据 影响table的展示效果
  const [Myloading, setMyloading] = useState(false);

  //当前需要显示的分类列表的id 是一级分类还是二级分类
  const [categoryId, setcategoryId] = useState("0");

  //当前需要显示的分类列表的父分类名称
  const [parentName, setparentName] = useState("");

  // showStatus控制显示框是否显示(更新或者添加分类) 控制对话框是否显示
  // 0表示俩都不显示 1表示添加框显示 2表示更新框显示
  const [showStatus, setshowStatus] = useState(0);

  // Form.useForm();用来获取下面表单form实例对象,作用和ref感觉一样
  // 第一个是更新表单的 第二个是新加数据的表单的
  const [formUpdate] = Form.useForm();
  const [formadd] = Form.useForm();

  // 查看子分类 需要获得当前的categoryId和parentName
  const ShowSubCategory = (text: any, record: any, index: any): void => {
    // 先更新状态
    // useState这个hooks不能异步改为同步执行
    // 所以这里西安修改categoryId和parentName 然后更新getCategorys放在下面的useEffect中
    setcategoryId(record._id);
    setparentName(record.name);
  };

  useEffect(() => {
    getCategorys();
    // categoryId修改时重新请求getCategorys更新数据内容 categoryId是0时候显示一级分类列表 1就显示二级分类列表
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [categoryId]);

  // 从后台获取数据并且添加到state categorys中,数据会单向流从而渲染到页面
  const getCategorys = async () => {
    // 在发送请求前要显示loading
    setMyloading(true);
    // 请求数据
    // 传入参数是usestaste的categoryId 表示是一级还是二级
    const res = await reqCategory(categoryId);
    // 请求结束之后 显示数据 不显示在发送请求前要显示loading
    // console.log(res);
    setMyloading(false);
    // 根据返回来更新内容
    if (res.data.status === 0) {
      // 取出分类数组 可能是一级也可能是二级的
      if (categoryId === "0") {
        // 如果categoryId是0说明更新一级列表
        setcategorys(res.data.data);
      } else {
        // 如果categoryId是1说明更新二级列表
        setsubCategory(res.data.data);
      }
    } else {
      message.error("获取列表分类失败");
    }
  };

  // 点击 "一级分类列表" 可以返回一级列表
  // 要再显示一级列表 只需要再设置setcategoryId('0')为0 setparentName('')设置空字符串
  // 以及把subCategory清空即可
  const showFirstCategory = () => {
    setcategoryId("0");
    setparentName("");
    setsubCategory([]);
  };

  // card右上角添加按钮的回调函数
  const showAdd = () => {
    //显示添加的对话框
    setshowStatus(1);
  };

  // table表内点击修改后显示出现修改的对话框
  const showUpdate = (text: any, record: any, index: any): void => {
    //显示修改的对话框
    setshowStatus(2);

    // 全局记录下当前点击的table行中的数据中的_id 用作传给后端更新名称的表示 暂时记录作用 因为想不到其他方法了
    settempId(record._id);
    // console.log(tempId);
  };
  // modal框点击取消的函数
  const handleCancel = () => {
    // 隐藏对话框
    setshowStatus(0);
  };

  // 添加分类对话框中点击OK的回调 点击后输入内容再点击OK会把输入的内容添加到后台数据库
  const addCategorys = async () => {
    try {
      // 首先做表单输入验证 add1 add2分别是添加表单中的下拉框和输入框
      // 获得两个input中的内容 1是下拉的内容 2是输入的内容
      const values1 = await formadd.validateFields(["add1"]);
      const values2 = await formadd.validateFields(["add2"]);

      // console.log("Success:", values1);
      // console.log("Success:", values2);

      // 获取当前输入框的内容 上面的下拉为values1.add1 下面输入的是values2.add2
      const parentId = values1.add1;
      const categoryName = values2.add2;

      // 注意后台接口的书写  因为我前端axios的请求把参数都封装进params这个对象了
      // 所以后台的获取前端传来的数据的时候要拆开params这个对象
      const res = await addCategory(parentId, categoryName);
      if (res.data.status === 0) {
        //res.data.status === 0表示后台接收数据并且更新成功 再次调用getCategorys更新数据
        getCategorys();
        // console.log(res);
      }
      //setshowStatus 隐藏对话框
      setshowStatus(0);
    } catch (errorInfo) {
      // 显示失败信息
      console.log("Failed:", errorInfo);
    }
  };

  // 更新分类名称对话框中点击OK的回调
  const updateCategoryName = async () => {
    // 输入进表单数据的验证 是否符合rules
    try {
      // 验证修改input中的输入符合rules与否
      const values = await formUpdate.validateFields(["update"]);
      // 成功的话输入的内容就存在values中
      console.log("Success:", values);
      // 点击后要再次隐藏对话框
      setshowStatus(0);
      // 把当前行的_id和输入的信息传给对应接口用作更新名称
      const res = await updateCategory(tempId, values.update);
      if (res.data.status === 0) {
        //res.data.status === 0表示后台接收数据并且更新成功 再次调用getCategorys更新数据
        getCategorys();
      }
    } catch (errorInfo) {
      console.log("Failed:", errorInfo);
    }
  };

  // 这里的title 需要根据当前的categoryId来确定
  // 如果是categoryId === "0"就展示一级分类列表 否则就显示二级分类列表
  const title =
    categoryId === "0" ? (
      "一级分类列表"
    ) : (
      <span>
        {/* 这里在二级分类列表的title上点击 "一级分类列表" 可以返回一级列表 */}
        <MyButton
          // 点击 "一级分类列表" 可以返回一级列表
          onClick={showFirstCategory}
          placeHolder="一级分类列表"
        ></MyButton>{" "}
        <ArrowRightOutlined style={{ marginRight: 10 }} />{" "}
        <span>{parentName}</span>
      </span>
    );

  // card右上角的添加按钮
  const exact = (
    <Button type="primary" onClick={showAdd}>
      <PlusOutlined />
      添加
    </Button>
  );

  // table列的定义
  const columns = [
    {
      title: "分类名称",
      dataIndex: "name",
      key: "name",
    },
    {
      title: "Action",
      dataIndex: "action",
      width: 380,
      key: "action",
      // 三个参数可以获得当前点击行的数据
      // 生成复杂数据的渲染函数，三个参数分别为当前行的值，当前行数据，行索引
      render: (text: any, record: any, index: any) => (
        <span>
          {/* 点击修改按钮 */}
          <MyButton
            onClick={() => {
              // text暂时不明,是undefined
              // 三个参数代表着 当前点击的table项的内容
              // record是当前项的所有内容 index是当前项的所以序号
              showUpdate(text, record, index);
            }}
            placeHolder="点击修改"
          ></MyButton>

          {/*如果categoryId是0说明是一级分类 如果不是0说明是二级分类 那么内部也就不需要查看子分类的按钮了*/}
          {categoryId === "0" ? (
            <MyButton
              // 如果在onClick里面绑定的函数是需要参数的,不能直接写函数(参数)的方式, 要写成回调的方式
              onClick={() => {
                // text暂时不明,是undefined
                // 三个参数代表着 当前点击的table项的内容
                // record是当前项的所有内容 index是当前项的所以序号
                ShowSubCategory(text, record, index);
              }}
              placeHolder="查看子分类"
            ></MyButton>
          ) : null}
        </span>
      ),
    },
  ];

  return (
    // 使用antd的Card
    <Card className="card-container" title={title} extra={exact}>
      {/* // 使用antd的table */}
      <Table
        // dataSource={categorys}
        dataSource={categoryId === "0" ? categorys : subCategory}
        columns={columns}
        bordered={true}
        // 为table中的每一项设置一个独立不重复的id 这里用的是mongodb中的_id 每次请求过来的数据都有这个_id 不写会有警告
        rowKey="_id"
        // 页面加载时候显示loading
        loading={Myloading}
        // 分页器pagination设置
        pagination={{ showQuickJumper: true }}
      />
      {/* // 添加分类的modal */}
      <Modal
        title="添加新的商品种类"
        visible={showStatus === 1 ? true : false}
        onOk={addCategorys}
        onCancel={handleCancel}
      >
        {/* 这里收集输入的form也组件化了,和category在一个文件夹中 */}
        <Form form={formadd}>
          <Form.Item
            name="add1"
            rules={[{ required: true, message: "请选择内容,不能为空。" }]}
          >
            <Select
              value={123}
              style={{ width: 470 }}
              placeholder="一级分类列表"
            >
              {/* 选择要添加到哪一级分类中 */}
              {categorys.map((c: any) => (
                <Option value={c._id} key={c._id}>
                  {c.name}
                </Option>
              ))}
            </Select>
          </Form.Item>

          <Form.Item
            name="add2"
            rules={[{ required: true, message: "请输入内容,不能为空。" }]}
          >
            <Input
              placeholder="请输入新的分类名称"
              type="text"
              value={"text"}
              style={{ width: 470 }}
            />
          </Form.Item>
        </Form>
      </Modal>
      {/* // 更新分类的modal */}
      <Modal
        title="更新已有商品名称"
        visible={showStatus === 2 ? true : false}
        onOk={updateCategoryName}
        onCancel={handleCancel}
      >
        {/* 这里收集输入的form也组件化了,和category在一个文件夹中 */}
        {/* <UpdatedForm ref={updateRef}></UpdatedForm> */}
        <Form form={formUpdate} name="dynamic_rule">
          <Form.Item
            name="update"
            rules={[{ required: true, message: "请输入内容,不能为空。" }]}
          >
            <Input
              placeholder="请输入更新后的商品分类名称"
              type="text"
              // value={""}
              style={{ width: 470 }}
            />
          </Form.Item>
        </Form>
      </Modal>
    </Card>
  );
};

export default Category;
